/*
 * Copyright 2002-2010 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.context.support;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;

/**
 * Standalone XML application context, taking the context definition files from the file
 * system or from URLs, interpreting plain paths as relative file system locations (e.g.
 * "mydir/myfile.txt"). Useful for test harnesses as well as for standalone environments.
 *
 * <p>
 * <b>NOTE:</b> Plain paths will always be interpreted as relative to the current VM
 * working directory, even if they start with a slash. (This is consistent with the
 * semantics in a Servlet container.) <b>Use an explicit "file:" prefix to enforce an
 * absolute file path.</b>
 *
 * <p>
 * The config location defaults can be overridden via {@link #getConfigLocations}, Config
 * locations can either denote concrete files like "/myfiles/context.xml" or Ant-style
 * patterns like "/myfiles/*-context.xml" (see the
 * {@link org.springframework.util.AntPathMatcher} javadoc for pattern details).
 *
 * <p>
 * Note: In case of multiple config locations, later bean definitions will override ones
 * defined in earlier loaded files. This can be leveraged to deliberately override certain
 * bean definitions via an extra XML file.
 *
 * <p>
 * <b>This is a simple, one-stop shop convenience ApplicationContext. Consider using the
 * {@link GenericApplicationContext} class in combination with an
 * {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader} for more flexible
 * context setup.</b>
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @see #getResource
 * @see #getResourceByPath
 * @see GenericApplicationContext
 */
public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {

	/**
	 * Create a new FileSystemXmlApplicationContext for bean-style configuration.
	 * 
	 * @see #setConfigLocation
	 * @see #setConfigLocations
	 * @see #afterPropertiesSet()
	 */
	public FileSystemXmlApplicationContext() {
	}

	/**
	 * Create a new FileSystemXmlApplicationContext for bean-style configuration.
	 * 
	 * @param parent the parent context
	 * @see #setConfigLocation
	 * @see #setConfigLocations
	 * @see #afterPropertiesSet()
	 */
	public FileSystemXmlApplicationContext(ApplicationContext parent) {
		super(parent);
	}

	/**
	 * Create a new FileSystemXmlApplicationContext, loading the definitions from the
	 * given XML file and automatically refreshing the context.
	 * 
	 * @param configLocation file path
	 * @throws BeansException if context creation failed
	 */
	public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
		this(new String[] { configLocation }, true, null);
	}

	/**
	 * Create a new FileSystemXmlApplicationContext, loading the definitions from the
	 * given XML files and automatically refreshing the context.
	 * 
	 * @param configLocations array of file paths
	 * @throws BeansException if context creation failed
	 */
	public FileSystemXmlApplicationContext(String... configLocations)
			throws BeansException {
		this(configLocations, true, null);
	}

	/**
	 * Create a new FileSystemXmlApplicationContext with the given parent, loading the
	 * definitions from the given XML files and automatically refreshing the context.
	 * 
	 * @param configLocations array of file paths
	 * @param parent the parent context
	 * @throws BeansException if context creation failed
	 */
	public FileSystemXmlApplicationContext(String[] configLocations,
			ApplicationContext parent) throws BeansException {
		this(configLocations, true, parent);
	}

	/**
	 * Create a new FileSystemXmlApplicationContext, loading the definitions from the
	 * given XML files.
	 * 
	 * @param configLocations array of file paths
	 * @param refresh whether to automatically refresh the context, loading all bean
	 *        definitions and creating all singletons. Alternatively, call refresh
	 *        manually after further configuring the context.
	 * @throws BeansException if context creation failed
	 * @see #refresh()
	 */
	public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh)
			throws BeansException {
		this(configLocations, refresh, null);
	}

	/**
	 * Create a new FileSystemXmlApplicationContext with the given parent, loading the
	 * definitions from the given XML files.
	 * 
	 * @param configLocations array of file paths
	 * @param refresh whether to automatically refresh the context, loading all bean
	 *        definitions and creating all singletons. Alternatively, call refresh
	 *        manually after further configuring the context.
	 * @param parent the parent context
	 * @throws BeansException if context creation failed
	 * @see #refresh()
	 */
	public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh,
			ApplicationContext parent) throws BeansException {
		// 为容器设置好Bean资源加载器
		super(parent);
		// 设置Bean定义资源文件的定位路径
		setConfigLocations(configLocations);
		if (refresh) {
			/**
			 * Spring IOC 容器对 Bean 定义资源的载入是从 refresh()函数开始的， refresh()是一个模板方法，
			 * refresh()方法的作用是： 在创建 IOC 容器前， 如果已经有容器存在， 则需要把已有的容器销毁和关闭， 以保证在 refresh
			 * 之后使用的是新建立起来的 IOC 容器。 refresh 的作用类似于对 IOC 容器的重启， 在 新建立好的容器中对容器进行初始化， 对 Bean
			 * 定义资源进行载入
			 */
			refresh();
		}
	}

	/**
	 * Resolve resource paths as file system paths.
	 * <p>
	 * Note: Even if a given path starts with a slash, it will get interpreted as relative
	 * to the current VM working directory. This is consistent with the semantics in a
	 * Servlet container.
	 * 
	 * @param path path to the resource
	 * @return Resource handle
	 * @see org.springframework.web.context.support.XmlWebApplicationContext#getResourceByPath
	 */
	@Override
	protected Resource getResourceByPath(String path) {
		if (path != null && path.startsWith("/")) {
			path = path.substring(1);
		}
		//这里使用文件系统资源对象来定义 bean 文件
		return new FileSystemResource(path);
	}

}
